package com.example.routercore.utils;

import com.example.routercore.thread.DefaultPoolExecutor;
import ohos.app.AbilityContext;
import ohos.rpc.RemoteException;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;

public class ClassUtils {
    /**
     * 路由表
     *
     * @param context
     * @param packageName
     * @return
     //* @throws PackageManager.NameNotFoundException
     * @throws InterruptedException
     */
    public static List<Class<?>> getFileNameByPackageName(AbilityContext context, final String
            packageName) throws
            InterruptedException,
            ClassNotFoundException,
            NoSuchMethodException,
            IllegalAccessException,
            InvocationTargetException,
            InstantiationException {
        //dalvik.system.DexFile无法直接引用，但是已经被加载到了内存中，所以用采用反射
        Class<?> dexFileClass = Class.forName("dalvik.system.DexFile");
        //获得dalvik.system.DexFile的构造方法
        Constructor dexFileConstructor = dexFileClass.getConstructor(String.class);
        //获得dalvik.system.DexFile的entries方法
        Method entriesMethod = dexFileClass.getMethod("entries");
        //获得dalvik.system.DexFile的close方法
        Method closeMethod = dexFileClass.getMethod("close");

        //获取hap文件的物理路径
        String bundleCodePath = context.getBundleCodePath();
        System.out.println("bundleCodePath=" + bundleCodePath);
        //准备存放dexFile的集合，考虑到可能会有多个hap文件
        Set dexFiles = new HashSet();
        File dir = new File(bundleCodePath).getParentFile();
        System.out.println("dir=" + dir.getAbsolutePath());
        File[] files = dir.listFiles();
        for (File file : files) {
            String absolutePath = file.getAbsolutePath();
            System.out.println(absolutePath);
            if (!absolutePath.contains(".")) {
                continue;
            }
            String suffix = absolutePath.substring(absolutePath.lastIndexOf("/"));
            if (!suffix.endsWith(".hap")) {
                continue;
            }
            //过滤完成，和Android类似，一个dexFile对应一个hap（apk）
            Object dexFileObj = dexFileConstructor.newInstance(absolutePath);
            if (dexFileObj != null) {
                dexFiles.add(dexFileObj);
            }
        }
        System.out.println("dexFiles.size()=" + dexFiles.size());

        //获取类加载器（本质上还是PathClassLoader）
        ClassLoader classLoader = context.getClassloader();
        //用来存放扫描到的class对象集合
        List<Class<?>> classList = new ArrayList<>();

        //使用同步计数器判断均处理完成
        final CountDownLatch parserCtl = new CountDownLatch(dexFiles.size());
        ThreadPoolExecutor threadPoolExecutor = DefaultPoolExecutor.newDefaultPoolExecutor(dexFiles.size());
        for (final Object dexFile : dexFiles) {
            threadPoolExecutor.execute(new Runnable() {

                @Override
                public void run() {
                    try {
                        //获取当前dexFile下面所有的类信息
                        Enumeration<String> entries = (Enumeration<String>) entriesMethod.invoke(dexFile);
                        //遍历过滤目标包名下的class
                        while (entries.hasMoreElements()) {
                            String className = entries.nextElement();
                            System.out.println(className);
                            if (className == null || className.isEmpty() || className.indexOf(packageName) != 0) {
                                continue;
                            }
                            Class<?> entryClass = Class.forName(className, true, classLoader);
                            if (entryClass != null) {
                                classList.add(entryClass);
                            }
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } finally {
                        if (null != dexFile) {
                            try {
                                closeMethod.invoke(dexFile);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                        //释放1个
                        parserCtl.countDown();
                    }
                }
            });
        }
        //等待执行完成
        parserCtl.await();
        return classList;
    }
}
